unit PathFinder;

interface

uses SysUtils, Paths, AsphyreSprite, AsphyreDef, Geometry, Math, Types, Vectors2;

type
TPath = array of TPoint;
TPathSeeker = class
private
  FMap:TMap;
  FStaticsMap:TStaticsMap;
//  FSize:double;
public
  property Map:TMap read FMap write FMap;
  function FindWay(StartPoint,EndPoint:TPoint):TPath;
  function WayClear(StartPoint,EndPoint:TPoint; WithDanger:boolean):boolean;
  procedure RecognizeMap(SE:TSpriteEngine);
end;

implementation
uses
ImpactSprite;

function TPathSeeker.WayClear(StartPoint,EndPoint:TPoint; WithDanger:boolean):boolean;
var
NormVect:TPoint2;
Len:real;
CurrentPoint:TPoint2;
i,z:integer;
begin
  NormVect.x:=EndPoint.X-StartPoint.X;
  NormVect.y:=EndPoint.y-StartPoint.y;
  len:=VecAbs2(NormVect);
  NormVect:=VecNorm2(NormVect);
  CurrentPoint.x:=StartPoint.x;
  CurrentPoint.y:=StartPoint.y;
  z:=0;
  if WithDanger then
  for i := 0 to round(len) do
  begin
    CurrentPoint:=VecAdd2(CurrentPoint,NormVect);
    if (round(FMap[trunc(CurrentPoint.x),trunc(CurrentPoint.y)].value)>1) then
    inc(z);
  end
  else
  begin
    CurrentPoint:=VecAdd2(CurrentPoint,NormVect);
    if FStaticsMap[trunc(CurrentPoint.x),trunc(CurrentPoint.y)] then
    inc(z);
  end;
  if z<=2 then
  Result:=true
  else
  Result:=false;
end;

procedure TPathSeeker.RecognizeMap(SE:TSpriteEngine);
var
i,j,k:integer;
Top,Right,Left,Bottom:real;
begin
  for i := 0 to MaxX do
  for j := 0 to MaxY do
  begin
    FMap[i,j].value:=1;
    FMap[i,j].TerrType:=ttClear;
    FStaticsMap[i,j]:=false;
  end;
  for i := 0 to SE.Count-1 do
  if SE[i] is TPhisicObject then
  if SE[i].DoCollision then
  if SE[i].CollideMethod=cmRadius then
  begin
    for j := trunc((SE[i].x+1024-SE[i].CollideRadius*2)/CellSize) to
      trunc((SE[i].x+1024+SE[i].CollideRadius*2)/CellSize+1) do
    for k := trunc((SE[i].y+1024-SE[i].CollideRadius*2)/CellSize) to
      trunc((SE[i].y+1024+SE[i].CollideRadius*2)/CellSize+1) do
    if SphereWithQuad(SE[i].X,SE[i].Y,SE[i].CollideRadius,
      pBounds4((j)*CellSize-1024,(k)*CellSize-1024,CellSize,CellSize)) then
    if InRange(j,0,MaxX) then
    if InRange(k,0,MaxY) then
    if not(SE[i] is TBullet) then
    begin
      FStaticsMap[j,k]:=true;
      if TPhisicObject(SE[i]).Mass=0 then
      begin
        FMap[j,k].TerrType:=ttWall;
        FMap[j,k].value:=10000;
      end
      else
      begin
        FMap[j,k].value:=Min(FMap[j,k].value+Max(TPhisicObject(SE[i]).Mass/
          20,1),10);
        FMap[j,k].TerrType:=Max(6-trunc(FMap[j,k].value)+1,1);
      end;
    end
    else
    begin
	    if TBullet(SE[i]).Unstopable then
	    begin
	      FMap[j,k].value:=Min(FMap[j,k].value+Max(TBullet(SE[i]).Weapon.Damage/
	        10,1),5);
	      FMap[j,k].TerrType:=Max(6-trunc(FMap[j,k].value)+1,1);
	    end
	    else
	    begin
	      FMap[j,k].value:=Min(FMap[j,k].value+Max(TBullet(SE[i]).Weapon.Damage/
	        10,1),5);
	      FMap[j,k].TerrType:=Max(6-trunc(FMap[j,k].value)+1,1);
	    end;
    end;
  end
  else
  begin
    Left:=Min(Min(Min(SE[i].CollideQuadrangle[0].x,
      SE[i].CollideQuadrangle[1].x),SE[i].CollideQuadrangle[2].x),
      SE[i].CollideQuadrangle[3].x);
    Right:=Max(Max(Max(SE[i].CollideQuadrangle[0].x,
      SE[i].CollideQuadrangle[1].x),SE[i].CollideQuadrangle[2].x),
      SE[i].CollideQuadrangle[3].x);
    Top:=Min(Min(Min(SE[i].CollideQuadrangle[0].y,
      SE[i].CollideQuadrangle[1].y),SE[i].CollideQuadrangle[2].y),
      SE[i].CollideQuadrangle[3].y);
    Bottom:=Max(Max(Max(SE[i].CollideQuadrangle[0].y,
      SE[i].CollideQuadrangle[1].y),SE[i].CollideQuadrangle[2].y),
      SE[i].CollideQuadrangle[3].y);
    for j := Max(Min(trunc((Left+1024)/CellSize),MaxX),0) to
      Max(Min(trunc((Right+1024)/CellSize+1),MaxX),0) do
    for k := Max(Min(trunc((Top+1024)/CellSize),MaxY),0) to
      Max(Min(trunc((Bottom+1024)/CellSize+1),MaxY),0) do
    if OverlapQuadrangle(SE[i].CollideQuadrangle,
      pBounds4(j*CellSize-1024,k*CellSize-1024,CellSize,CellSize)) then
    begin
	    if not(SE[i] is TBullet) then
	    begin
        FStaticsMap[j,k]:=true;
	      if TPhisicObject(SE[i]).Mass=0 then
	      begin
	        FMap[j,k].TerrType:=ttWall;
	        FMap[j,k].value:=10000;
	      end
	      else
	      begin
	        FMap[j,k].value:=Min(FMap[j,k].value+Max(1*TPhisicObject(SE[i]).Mass/
	          20,1),10);
  	      FMap[j,k].TerrType:=Max(6-trunc(FMap[j,k].value)+1,1);
	      end;
      end
	    else
	    begin
		    if TBullet(SE[i]).Unstopable then
		    begin
		      FMap[j,k].value:=Min(FMap[j,k].value+Max(TBullet(SE[i]).Weapon.Damage/
		        100,1),5);
		      FMap[j,k].TerrType:=Max(6-trunc(FMap[j,k].value)+1,1);
		    end
		    else
		    begin
		      FMap[j,k].value:=Min(FMap[j,k].value+Max(TBullet(SE[i]).Weapon.Damage/
		        100,1),5);
		      FMap[j,k].TerrType:=Max(6-trunc(FMap[j,k].value)+1,1);
		    end;
	    end;
    end;
  end;
end;

function TPathSeeker.FindWay(StartPoint,EndPoint:TPoint):TPath;
var
  Found:boolean;
  C:TPoint;
  i,j,z:integer;
  Path:TPath;
begin
  for i:=0 to MaxX do
    for j:=0 to MaxY do
    FMap[i,j].Status:=tsUnvisited;
{  FMap[StartPoint.x,StartPoint.y].TerrType:=6;
  FMap[StartPoint.x,StartPoint.y].value:=1;
  FMap[EndPoint.x,EndPoint.y].TerrType:=6;
  FMap[EndPoint.x,EndPoint.y].value:=1;      }
  Found:=FindPath(StartPoint,EndPoint,FMap);
  z:=0;
  if found then
  begin
    c:=FMap[EndPoint.X,EndPoint.Y].Prev;
    While not EqualPoints(c,StartPoint) and InRange(c.x,0,MaxX)and InRange(c.y,
      0,MaxY) do
    begin
      inc(z);
      SetLength(Path,z);
      if FMap[c.X,c.y].Status<>tsBound then
       FMap[c.X,c.y].Status:=tsPath;
      Path[z-1]:=c;
      c:=FMap[c.x,c.y].Prev;
      if z>255 then
      exit;
    end;
    result:=Path;
  end;
end;

end.
